package io.afu.httprequest;


import com.fasterxml.jackson.databind.ObjectMapper;
import io.afu.common.constant.CommonConstant;
import io.afu.common.constant.ConstantEnum;
import io.afu.common.exception.BaseException;
import io.afu.common.exception.ParamsException;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;


import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HttpRequest {

    private Map<String,String> headers;

    private Map<String,Object> params;

    private String url;

    private String fullUrl; // 仅在Get方生效

    private String charset = StandardCharsets.UTF_8.toString();

    private CloseableHttpClient httpClient = HttpClients.createDefault();

    private HttpEntity stringEntity;

    private Map<String,String> filePath;

    private Map<String,byte[]> fileBytes;


    public Map<String, byte[]> getFileBytes() {
        return fileBytes;
    }

    public void setFileBytes(Map<String, byte[]> fileBytes) {
        this.fileBytes = fileBytes;
    }

    public Map<String, String> getHeaders() {
        return headers;
    }

    public void setHeaders(Map<String, String> headers) {
        this.headers = headers;
    }

    public Map<String, Object> getParams() {
        return params;
    }

    public HttpRequest setParams(Map<String, Object> params) {
        this.params = params;
        return this;
    }


    public String getUrl() {
        if (fullUrl != null){
            return fullUrl;
        }
        return url;
    }

    public HttpRequest setUrl(String url) {
        this.url = url;
        return this;
    }

    public HttpEntity getStringEntity() {
        return stringEntity;
    }

    public HttpRequest setStringEntity(HttpEntity stringEntity) {
        this.stringEntity = stringEntity;
        return this;
    }

    public String getCharset() {
        return charset;
    }

    public void setCharset(String charset) {
        this.charset = charset;
    }

    public static HttpRequest getInstance(){
        return new HttpRequest();
    }

    public HttpRequest(){
        setDefaultUserAgent();
    }



    /**
     * Get 专用的URL生成器
     * @throws BaseException 抛错
     */
    private void makeGetUrl() throws BaseException {
        if (getUrl() == null || getUrl().equals("")){
            throw new ParamsException();
        }
        String url = getUrl();
        if (getParams() == null || getParams().size() ==0){
            this.fullUrl = this.url;
            return;
        }
        Map<String,Object> params = getParams();
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(url);
        stringBuilder.append("?");
        List<String> keys = new ArrayList<>();
        keys.addAll(params.keySet());
        for (int i =0;i<keys.size();i++){
            stringBuilder.append(keys.get(i));
            stringBuilder.append("=");
            try {
                stringBuilder.append(URLEncoder.encode(params.get(keys.get(i)).toString(), charset));
            }catch (Exception e){
                throw new BaseException(e);
            }
            if (i!=keys.size()-1){
                stringBuilder.append("&");
            }
        }
        this.fullUrl = stringBuilder.toString();
        return;
    }

    /**
     * 添加Header
     * @param key key
     * @param value value
     * @return 返回类本身
     */
    public HttpRequest addHeader(String key,String value){
        if (headers == null){
            headers = new HashMap<>();
        }
        headers.put(key,value);
        return this;
    }

    /**
     * 添加cookie
     * @param key key
     * @param value value
     * @return 返回类本身
     */
    public HttpRequest addCookie(String key,String value){
        if (headers == null){
            headers = new HashMap<>();
        }
        String cookieContent = headers.get("Cookie");
        if (cookieContent == null || cookieContent.equals("")){
            cookieContent = key+"="+value;
        }else {
            cookieContent+= ";"+key+"="+value;
        }
        headers.put("Cookie",cookieContent);
        return this;
    }

    /**
     * 添加参数
     * @param key key
     * @param value value
     * @return 返回本类
     */
    public HttpRequest addParam(String key,Object value){
        if (params == null){
            params = new HashMap<>();
        }
        params.put(key,value);
        return this;
    }

    public HttpRequest addFile(String name,String filePath){
        if (this.filePath == null){
            this.filePath = new HashMap<>();
        }
        this.filePath.put(name,filePath);
        return this;
    }

    /**
     * 使用JSON请求
     * @return 类
     */
    public HttpRequest useJson(){
        addHeader("Content-Type","application/json;charset=UTF-8");
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            this.stringEntity = new StringEntity(objectMapper.writeValueAsString(getParams()),getCharset());
        }catch (Exception e){
            e.printStackTrace();
        }
        return this;
    }
    public HttpRequest useWebService(){
        addHeader("Content-Type","application/soap+xml; charset=utf-8");
        return this;
    }

    /**
     * 使用FormData请求
     * @return 类
     */
    public HttpRequest useFormData(){
        List<NameValuePair> clientParams = new ArrayList<>();
        for (Map.Entry<String,Object> entry:getParams().entrySet()){
            clientParams.add(new BasicNameValuePair(entry.getKey(),entry.getValue().toString()));
        }
        try {
            this.stringEntity = new UrlEncodedFormEntity(clientParams,getCharset());
        }catch (Exception e){
            e.printStackTrace();
        }
        return this;
    }

    public HttpRequest useUrlParam() throws BaseException {
        makeGetUrl();
        return this;
    }

    /**
     * 使用文件请求
     * @return 类
     */
    public HttpRequest useMultiPartUpload(){
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        if (params != null && params.size()>0){
            for (Map.Entry<String,Object> entry:params.entrySet()){
                builder.addTextBody(entry.getKey(),entry.getValue().toString());
            }
        }
        if (filePath != null && filePath.size() >0){
            for (Map.Entry<String,String> entry:filePath.entrySet()){
                builder.addPart(entry.getKey(),new FileBody(new File(entry.getValue())));
            }
        }
        if (fileBytes != null && fileBytes.size()>0){
            for (Map.Entry<String,byte[]> entry:fileBytes.entrySet()){
                String suffix = FileUtils.getFileSuffixSubstringWay(entry.getKey());
                String content = FileUtils.getFileContentTypeBySuffix(suffix);
                ContentType contentType = ContentType.create(content,StandardCharsets.UTF_8.toString());
                builder.addBinaryBody("file",entry.getValue(),contentType,entry.getKey());
            }
        }
        this.stringEntity = builder.build();
        return this;
    }

    /**
     * 设置默认的User-Agent
     */
    private void setDefaultUserAgent(){
        if (headers == null){
            headers = new HashMap<>();
        }
        String ua = headers.get("User-Agent");
        if (ua == null || ua.equals("") ){
            ua = CommonConstant.USER_AGENT;
            headers.put("User-Agent",ua);
        }
    }

    public void neededParam() throws BaseException{
        if (this.url == null){
            throw new BaseException(ConstantEnum.REQUEST_URL_NOT_SET);
        }
    }


    /**
     * 关闭默认的HttpClient
     */
    private void closeHttpClient(){
        if (httpClient != null){
            try {
                httpClient.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    private void closeHttpResponse(CloseableHttpResponse response){
        if (response != null){
            try {
                response.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public String get(String url) {
        this.url = url;
        return get();
    }

    public String get(){
        String result = null ;

        try {
            makeGetUrl();
            HttpGet httpGet = new HttpGet(fullUrl);
            if (headers != null && headers.size()>0){
                for (Map.Entry<String,String> entry:getHeaders().entrySet()){
                    httpGet.setHeader(entry.getKey(),entry.getValue());
                }
            }
            CloseableHttpResponse response= httpClient.execute(httpGet);
            try {
                HttpEntity entity = response.getEntity();
                result = EntityUtils.toString(entity,charset);
                System.out.println("[请求URL:"+fullUrl+"]结果为:["+result+"]");
            }catch (Exception e){
                throw new BaseException(e);
            }finally {
                if (httpClient != null){
                    try {
                        httpClient.close();
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        closeHttpClient();
        return result;
    }

    public String post(String url) {
        this.url = url;
        return post();
    }

    public String post(){
        String result = null ;
        try {
            HttpPost httpPost = new HttpPost(getUrl());
            if (getHeaders()!= null){
                for (Map.Entry<String,String> entry:getHeaders().entrySet()){
                    httpPost.setHeader(entry.getKey(),entry.getValue());
                }
            }
            if (stringEntity == null){
                useJson();
            }
            httpPost.setEntity(stringEntity);
            CloseableHttpResponse response = httpClient.execute(httpPost);
            try {
                HttpEntity entity = response.getEntity();
                result = EntityUtils.toString(entity,getCharset());
                System.out.println("[请求URL:"+getUrl()+"]结果为:["+result+"]");
            }catch (Exception e){
                e.printStackTrace();
            }
            closeHttpResponse(response);
        }catch (Exception e){
            e.printStackTrace();
        }
        closeHttpClient();
        return result;
    }

    public String put(){
        String result = null ;

        closeHttpClient();
        return result;
    }

    public String delete(){
        String result = null ;

        closeHttpClient();
        return result;
    }











}
